<!--
 * @Description: 滚动容器，提供滚动底部/滚动监听/缓存
 * @Author bianpengfei
 * @create 2021/12/27 20:58
 -->
<!--default-->
<script>
export default { name: 'g-scroll-view-simple' }
</script>

<!--setup-->
<script setup>
import { onMounted, onUnmounted, reactive, onActivated, onDeactivated, ref } from 'vue'
import { Base, Dom } from '@bianpengfei/utils'
import { useRoute } from 'vue-router'
import { position } from './position'

const { routePosition } = position

const { throttle, debounce } = Base

const props = defineProps({
  height: {
    type: String,
    default: '100vh'
  },
  showScrollBar: {
    // 是否展示滚动条
    type: Boolean,
    default: false
  },
  enabledScrollListener: {
    // 是否开启滚动监听
    type: Boolean,
    default: true
  },

  showBackTop: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['on-scroll', 'on-scroll-to-bottom'])
const scrollViewRef = ref(null)
const state = reactive({
  uniqueClassName: ''
})

const route = useRoute()

let _throttledScrollHandler = null // 截流滚动
let _debounceScrollHandler = null // 去抖滚动

const uniqueKeyTemp = Base.UUID()
const _key = `${route.fullPath}||${uniqueKeyTemp}_${Number(new Date()).toString()}`
state.uniqueClassName = uniqueKeyTemp.replaceAll('.', '-')

onActivated(() => {
  const scrollTop = routePosition[_key]?.y || 0
  if (scrollTop) {
    setScrollTop(scrollTop)
  }
})

onDeactivated(() => {
  routePosition[_key] = {
    x: 0,
    y: scrollViewRef.value?.scrollTop
  }
  console.log({ routePosition })
})

onMounted(() => {
  if (props.enabledScrollListener) {
    _throttledScrollHandler = throttle(handleScroll, 20)
    _debounceScrollHandler = debounce(deScrollToBottom, 300)
    scrollViewRef.value.addEventListener('scroll', _throttledScrollHandler)
  }
})

onUnmounted(() => {
  delete routePosition[_key]
  scrollViewRef.value && scrollViewRef.value.removeEventListener('scroll', _throttledScrollHandler)
})

/**
 * 滚动
 */
const handleScroll = () => {
  const scrollTop = scrollViewRef.value.scrollTop
  const windowHeight = scrollViewRef.value.clientHeight
  const scrollHeight = scrollViewRef.value.scrollHeight
  emit('on-scroll', scrollTop)
  _debounceScrollHandler && _debounceScrollHandler(scrollTop, windowHeight, scrollHeight)
}

/**
 * 监听是否滚动到了底部
 * @param scrollTop
 * @param windowHeight
 * @param scrollHeight
 */
const deScrollToBottom = (scrollTop, windowHeight, scrollHeight) => {
  /*fix 重新请求导致底部重新加载问题*/
  if (scrollTop && scrollHeight - scrollTop - windowHeight < 35) {
    console.warn('[warn：已经滚动到底部了]')
    emit('on-scroll-to-bottom')
  }
}

/**
 * 设置scrollTop
 * @param {Number}  scrollTop
 */
const setScrollTop = (scrollTop = 0) => {
  setTimeout(() => {
    Dom.requestAnimationFrame(() => {
      scrollViewRef.value.scrollTop = scrollTop
    })
  }, 16)
}
</script>

<!--render-->
<template>
  <div>
    <g-backtop :target="`.${state.uniqueClassName}`" v-if="props.showBackTop"></g-backtop>
    <div
      :class="{
        'scroll-view': true,
        'div--webkit--scrollbar': true,
        'scroll-view--scrollbar-none': !props.showScrollBar,
        [state.uniqueClassName]: true
      }"
      :style="{ height: height }"
      ref="scrollViewRef"
    >
      <slot><div>内容区</div></slot>
    </div>
  </div>
</template>

<!--style-->
<style scoped lang="less">
.scroll-view {
  over-flow: auto; /* winphone8和android4+ */
  -webkit-overflow-scrolling: touch; /* ios5+ */
  overflow: hidden auto;
  .ios-bounce-android;
  .div--webkit--scrollbar();
}
.scroll-view--scrollbar-none {
  &::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
    color: transparent;
  }
}
</style>
